home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / linux-bo / etherboo.000 / etherboo / etherboot-2.0 / netboot-freebsd / main.c < prev    next >
C/C++ Source or Header  |  1996-06-18  |  19KB  |  661 lines

  1. /**************************************************************************
  2. NETBOOT -  BOOTP/TFTP Bootstrap Program
  3.  
  4. Author: Martin Renters
  5.   Date: Dec/93
  6.  
  7. **************************************************************************/
  8.  
  9. /* #define MDEBUG */
  10.  
  11. #include "netboot.h"
  12.  
  13. int    jmp_bootmenu[10];
  14.  
  15. struct    exec head;
  16. char    *loadpoint;
  17. char    *kernel;
  18. char    kernel_buf[128];
  19. void    (*kernelentry)();
  20. struct    nfs_diskless nfsdiskless;
  21. int    hostnamelen;
  22. char    config_buffer[TFTP_MAX_PACKET+1];    /* +1 for null byte */
  23. struct    bootinfo bootinfo;
  24. unsigned long    netmask;
  25.  
  26. char    broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  27.  
  28. /**************************************************************************
  29. MAIN - Kick off routine
  30. **************************************************************************/
  31. #ifdef __linux
  32. extern int main P((void));
  33. int _main() {return main();}
  34. #endif
  35.  
  36. int main()
  37. {
  38.     extern char *linux_add_cmdline();
  39.     char *p;
  40.     for (p=_edata; p<_end; p++) *p = 0;    /* Zero BSS */
  41. #ifdef ASK_BOOT
  42.     while (1) {
  43.         int c;
  44.         printf("\n\rBoot from Network (Y/N) ? ");
  45.         c = getchar();
  46.         if ((c >= 'a') && (c <= 'z')) c &= 0x5F;
  47.         if (c == '\r') break;
  48.         putchar(c);
  49.         if (c == 'N')
  50.             exit(0);
  51.         if (c == 'Y')
  52.             break;
  53.         printf(" - bad response\n\r");
  54.     }
  55. #endif
  56.     gateA20();
  57. #ifdef    NETBOOT32
  58.     printf("\r\nBOOTP/TFTP/NFS bootstrap loader " VERSION " ESC for menu\r\n\r\nSearching for adapter...");
  59. #endif
  60. #ifdef    NETBOOT16
  61. /* bcc still doesn't do ANSI string concatenation so this is hardwired */
  62.     printf("\r\nBOOTP/TFTP/NFS bootstrap loader 2.0 ESC for menu\r\n\r\nSearching for adapter...");
  63. #endif
  64.     if (!eth_probe()) {
  65.         printf("No adapter found.\r\n");
  66.         exit(0);
  67.     }
  68.     kernel = DEFAULT_BOOTFILE;
  69.     linux_add_cmdline(0); /* clear linux cmdline */
  70.     while (1) {
  71.         if (setjmp(jmp_bootmenu))
  72.             bootmenu();
  73.         else
  74.             load();
  75.     }
  76. }
  77.  
  78. #ifdef    NETBOOT32
  79. /**************************************************************************
  80. DOMOUNT - Try to mount FS
  81. **************************************************************************/
  82. void domount(char *s,int *port,int *mount_port,char *hostnam,char *fh,int arpserver,
  83.                 struct sockaddr_in *in_saddr,struct nfs_args *args,char *fnam,
  84.                 char *newfh)
  85. {
  86.     int err;
  87.     *port = rpclookup(arpserver, PROG_NFS, 2);
  88.     *mount_port = rpclookup(arpserver, PROG_MOUNT, 1);
  89.     if ((*port == -1) || (*mount_port == -1)) {
  90.         printf("Unable to get %s NFS/MOUNT ports\r\n",s);
  91.     bootmenu:
  92.         longjmp(jmp_bootmenu,1); }
  93.     if ((err = nfs_mount(arpserver, *mount_port, hostnam, fh))) {
  94.         printf("Unable to mount %s filesystem: ",s);
  95.     nfserr:
  96.         nfs_err(err);
  97.         goto bootmenu; }
  98.     in_saddr->sin_len = sizeof(struct sockaddr_in);
  99.     in_saddr->sin_family = AF_INET;
  100.     in_saddr->sin_port = htons(*port);
  101.     in_saddr->sin_addr.s_addr = htonl(arptable[arpserver].ipaddr);
  102.     args->timeo = 10;
  103.     args->retrans = 100;
  104.     if ((err = nfs_lookup(arpserver,*port,fh,fnam,newfh))) {
  105.         printf("Unable to open %s: ",fnam);
  106.         goto nfserr; }
  107.     return;
  108. }
  109. #endif    /* NETBOOT32 */
  110.  
  111. /**************************************************************************
  112. LOAD - Try to get booted
  113. **************************************************************************/
  114. void load()
  115. {
  116.     char    *p,*q;
  117.     char    cfg[64];
  118.     int    root_nfs_port;
  119.     int    root_mount_port;
  120.     int    swap_nfs_port;
  121.     int    swap_mount_port;
  122.     char    kernel_handle[32];
  123.     char    cmd_line[80];
  124.     int    err, offset, read_size;
  125.     long    addr, broadcast;
  126.  
  127. /* Initialize this early on */
  128.  
  129.         nfsdiskless.root_args.rsize = 8192;
  130.         nfsdiskless.root_args.wsize = 8192;
  131.         nfsdiskless.swap_args.rsize = 8192;
  132.         nfsdiskless.swap_args.wsize = 8192;
  133.         nfsdiskless.root_args.sotype = SOCK_DGRAM;
  134.         nfsdiskless.root_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE);
  135.         nfsdiskless.swap_args.sotype = SOCK_DGRAM;
  136.         nfsdiskless.swap_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE);
  137.  
  138.  
  139.         /* Find a server to get BOOTP reply from */
  140.     if (!arptable[ARP_CLIENT].ipaddr || !arptable[ARP_SERVER].ipaddr) {
  141.         printf("\r\nSearching for server...\r\n");
  142.         if (!bootp()) {
  143.             printf("No Server found.\r\n");
  144.         bootmenu:
  145.             longjmp(jmp_bootmenu,1);
  146.         }
  147.     }
  148.     printf("My IP %I, Server IP %I, GW IP %I\r\n",
  149.         arptable[ARP_CLIENT].ipaddr,
  150.         arptable[ARP_SERVER].ipaddr,
  151.         arptable[ARP_GATEWAY].ipaddr);
  152.  
  153. #ifdef MDEBUG
  154.     printf("\n=>>"); getchar();
  155. #endif
  156.  
  157.         /* Now use TFTP to load configuration file */
  158. #if defined(PRIORIZEBOOTPKERNEL) && !defined(BOOTPKERNELONLY)
  159.     printf(" \r\nLoading %s... ",kernel);
  160.     if (!tftp(kernel)) {
  161. #endif
  162. #ifndef BOOTPKERNELONLY
  163.     sprintf(cfg,"cfg.%I",arptable[ARP_CLIENT].ipaddr);
  164.     printf(" \r\nLoading %s... ",cfg);
  165.     if (!tftp(cfg)) {
  166.         sprintf(cfg,"/tftpboot/cfg.%I",arptable[ARP_CLIENT].ipaddr);
  167.         printf(" \r\nLoading %s... ",cfg);
  168.         if (!tftp(cfg)) {
  169. #endif
  170. #ifndef PRIORIZEBOOTPKERNEL
  171.             printf(" \r\nLoading %s... ",kernel);
  172.             if (!tftp(kernel)) {
  173. #endif
  174.                 printf("Unable to load config file.\r\n");
  175.                 goto bootmenu;
  176. #if !defined(PRIORIZEBOOTPKERNEL) || \
  177.          defined(PRIORIZEBOOTPKERNEL) && !defined(BOOTPKERNELONLY)
  178.  }
  179. #endif
  180. #ifndef BOOTPKERNELONLY
  181.     }    }
  182. #endif
  183.  
  184. #ifdef    NETBOOT32
  185. #ifdef MDEBUG
  186.     printf("\n=>>"); getchar();
  187. #endif
  188.  
  189.     p = config_buffer;
  190.     while(*p) {
  191.         q = cmd_line;
  192.         while ((*p != '\n') && (*p)) *(q++) = *(p++);
  193.         *q = 0;
  194.         printf("%s\r\n",cmd_line);
  195.         execute(cmd_line);
  196.         if (*p) p++;
  197.     }
  198.  
  199. #ifdef MDEBUG
  200.     printf("\n=>>"); getchar();
  201. #endif
  202.  
  203.         /* Check to make sure we've got a rootfs */
  204.     if (!arptable[ARP_ROOTSERVER].ipaddr) {
  205.         printf("No ROOT filesystem server!\r\n");
  206.         goto bootmenu;
  207.     }
  208.  
  209.         /* Fill in nfsdiskless.myif */
  210.     sprintf(&nfsdiskless.myif.ifra_name,eth_driver);
  211.         nfsdiskless.myif.ifra_addr.sa_len = sizeof(struct sockaddr);
  212.         nfsdiskless.myif.ifra_addr.sa_family = AF_INET;
  213.     addr = htonl(arptable[ARP_CLIENT].ipaddr);
  214.     bcopy(&addr, &nfsdiskless.myif.ifra_addr.sa_data[2], 4);
  215.     broadcast = (addr & netmask) | ~netmask;
  216.     nfsdiskless.myif.ifra_broadaddr.sa_len = sizeof(struct sockaddr);
  217.     nfsdiskless.myif.ifra_broadaddr.sa_family = AF_INET;
  218.     bcopy(&broadcast, &nfsdiskless.myif.ifra_broadaddr.sa_data[2], 4);
  219.     addr = htonl(arptable[ARP_GATEWAY].ipaddr);
  220.     if (addr) {
  221.         nfsdiskless.mygateway.sin_len = sizeof(struct sockaddr);
  222.         nfsdiskless.mygateway.sin_family = AF_INET;
  223.         bcopy(&addr, &nfsdiskless.mygateway.sin_addr, 4);
  224.     } else {
  225.         nfsdiskless.mygateway.sin_len = 0;
  226.     }
  227.     nfsdiskless.myif.ifra_mask.sa_len = sizeof(struct sockaddr);
  228.     nfsdiskless.myif.ifra_mask.sa_family = AF_UNSPEC;
  229.     bcopy(&netmask, &nfsdiskless.myif.ifra_mask.sa_data[2], 4);
  230.  
  231.     rpc_id = currticks();
  232.  
  233.         /* Lookup NFS/MOUNTD ports for SWAP using PORTMAP */
  234.     if (arptable[ARP_SWAPSERVER].ipaddr) {
  235.         char swapfs_fh[32], swapfile[32];
  236.         sprintf(swapfile,"swap.%I",arptable[ARP_CLIENT].ipaddr);
  237.         domount("SWAP",&swap_nfs_port,&swap_mount_port,nfsdiskless.swap_hostnam,
  238.                         swapfs_fh,ARP_SWAPSERVER,&nfsdiskless.swap_saddr,
  239.                         &nfsdiskless.swap_args,swapfile,nfsdiskless.swap_fh); }
  240.  
  241.         /* Lookup NFS/MOUNTD ports for ROOT using PORTMAP */
  242.     domount("ROOT",&root_nfs_port,&root_mount_port,nfsdiskless.root_hostnam,
  243.                     nfsdiskless.root_fh,ARP_ROOTSERVER,&nfsdiskless.root_saddr,
  244.                     &nfsdiskless.root_args,*kernel == '/' ? kernel+1 : kernel,
  245.                     kernel_handle);
  246.     nfsdiskless.root_time = 0;
  247.  
  248.         /* Load the kernel using NFS */
  249.     printf("Loading %s...\r\n",kernel);
  250.     if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port, (char *)&kernel_handle, 0,
  251.         sizeof(struct exec), (char *)&head)) < 0) {
  252.         printf("Unable to read %s: ",kernel);
  253.         nfs_err(err);
  254.         goto bootmenu;
  255.     }
  256.     if (N_BADMAG(head) &&
  257.         !load_linux(root_mount_port,swap_mount_port,
  258.             root_nfs_port,kernel_handle)) {
  259.         printf("Bad executable format!\r\n");
  260.         goto bootmenu;
  261.     }
  262.     loadpoint = (char *)0x100000;
  263.     offset = N_TXTOFF(head);
  264.     /* printf("text=0x%X, ",head.a_text); */
  265.     while (head.a_text > 0) {
  266.         read_size = head.a_text > NFS_READ_SIZE ?
  267.                 NFS_READ_SIZE : head.a_text;
  268.         if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port,
  269.             (char *)&kernel_handle, offset, read_size, loadpoint)) !=
  270.                 read_size) {
  271.             if (err < 0) {
  272.               /* printf("Unable to read text: "); */
  273.                 nfs_err(err);
  274.             }
  275.             goto bootmenu;
  276.         }
  277.         loadpoint += err;
  278.         head.a_text -= err;
  279.         offset += err;
  280.     }
  281.     while (((int)loadpoint) & CLOFSET)
  282.         *(loadpoint++) = 0;
  283.     /* printf("data=0x%X, ",head.a_data); */
  284.     while (head.a_data > 0) {
  285.         read_size = head.a_data > NFS_READ_SIZE ?
  286.                 NFS_READ_SIZE : head.a_data;
  287.         if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port,
  288.             (char *)&kernel_handle, offset, read_size, loadpoint)) !=
  289.                 read_size) {
  290.             if (err < 0) {
  291.               /* printf("Unable to read data: "); */
  292.                 nfs_err(err);
  293.             }
  294.             goto bootmenu;
  295.         }
  296.         loadpoint += err;
  297.         head.a_data -= err;
  298.         offset += err;
  299.     }
  300.     /* printf("bss=0x%X, ",head.a_bss); */
  301.     while(head.a_bss--) *(loadpoint++) = 0;
  302.  
  303.     /* printf("entry=0x%X.\n\r",head.a_entry); */
  304.  
  305.         /* Jump to kernel */
  306.     bootinfo.bi_version = BOOTINFO_VERSION;
  307.     bootinfo.bi_kernelname = kernel;
  308.     bootinfo.bi_nfs_diskless = &nfsdiskless;
  309.     kernelentry = (void *)(head.a_entry & 0x00FFFFFF);
  310.     (*kernelentry)(0,NODEV,0,0,0,&bootinfo,0,0,0);
  311.     /* printf("*** %s execute failure ***\n",kernel); */
  312. #endif    /* NETBOOT32 */
  313. }
  314.  
  315. /**************************************************************************
  316. POLLKBD - Check for Interrupt from keyboard
  317. **************************************************************************/
  318. void pollkbd()
  319. {
  320.     if (iskey() && (getchar() == ESC)) longjmp(jmp_bootmenu,1);
  321. }
  322.  
  323. /**************************************************************************
  324. DEFAULT_NETMASK - Set a default netmask for IP address
  325. **************************************************************************/
  326. void default_netmask()
  327. {
  328.     int net = arptable[ARP_CLIENT].ipaddr >> 24;
  329.     if (net <= 127)
  330.         netmask = htonl(0xff000000);
  331.     else if (net < 192)
  332.         netmask = htonl(0xffff0000);
  333.     else
  334.         netmask = htonl(0xffffff00);
  335. }
  336. /**************************************************************************
  337. UDP_TRANSMIT - Send a UDP datagram
  338. **************************************************************************/
  339. int udp_transmit(destip, srcsock, destsock, len, buf)
  340.     unsigned long destip;
  341.     unsigned int srcsock, destsock;
  342.     int len;
  343.     char *buf;
  344. {
  345.     struct iphdr *ip;
  346.     struct udphdr *udp;
  347.     struct arprequest arpreq;
  348.     int arpentry, i;
  349.     int retry = MAX_ARP_RETRIES;
  350.  
  351.     ip = (struct iphdr *)buf;
  352.     udp = (struct udphdr *)(buf + sizeof(struct iphdr));
  353.     ip->verhdrlen = 0x45;
  354.     ip->service = 0;
  355.     ip->len = htons(len);
  356.     ip->ident = 0;
  357.     ip->frags = 0;
  358.     ip->ttl = 60;
  359.     ip->protocol = IP_UDP;
  360.     ip->chksum = 0;
  361.     convert_ipaddr(ip->src, (char *)&arptable[ARP_CLIENT].ipaddr);
  362.     convert_ipaddr(ip->dest, (char *)&destip);
  363.     ip->chksum = ipchksum((unsigned short *)buf, sizeof(struct iphdr));
  364.     udp->src = htons(srcsock);
  365.     udp->dest = htons(destsock);
  366.     udp->len = htons(len - sizeof(struct iphdr));
  367.     udp->chksum = 0;
  368.     if (destip == IP_BROADCAST) {
  369.         eth_transmit(broadcast, IP, len, buf);
  370.     } else {
  371.         long h_netmask = ntohl(netmask);
  372.                 /* Check to see if we need gateway */
  373.         if (((destip & h_netmask) !=
  374.             (arptable[ARP_CLIENT].ipaddr & h_netmask)) &&
  375.             arptable[ARP_GATEWAY].ipaddr)
  376.                 destip = arptable[ARP_GATEWAY].ipaddr;
  377.         for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
  378.             if (arptable[arpentry].ipaddr == destip) break;
  379.         if (arpentry == MAX_ARP) {
  380.             printf("\r\n%I is not in my arp table!\r\n", destip);
  381.             return(0);
  382.         }
  383.         for (i = 0; i<ETHER_ADDR_SIZE; i++)
  384.             if (arptable[arpentry].node[i]) break;
  385.         if (i == ETHER_ADDR_SIZE) {    /* Need to do arp request */
  386.             arpreq.hwtype = htons(1);
  387.             arpreq.protocol = htons(IP);
  388.             arpreq.hwlen = ETHER_ADDR_SIZE;
  389.             arpreq.protolen = 4;
  390.             arpreq.opcode = htons(ARP_REQUEST);
  391.             bcopy(arptable[ARP_CLIENT].node, arpreq.shwaddr,
  392.                 ETHER_ADDR_SIZE);
  393.             convert_ipaddr(arpreq.sipaddr,
  394.                 (char *)&arptable[ARP_CLIENT].ipaddr);
  395.             bzero(arpreq.thwaddr, ETHER_ADDR_SIZE);
  396.             convert_ipaddr(arpreq.tipaddr, (char *)&destip);
  397.             while (retry--) {
  398.                 eth_transmit(broadcast, ARP, sizeof(arpreq),
  399.                     (char *)&arpreq);
  400.                 if (await_reply(AWAIT_ARP, arpentry,
  401.                     arpreq.tipaddr)) goto xmit;
  402.             }
  403.             return(0);
  404.         }
  405. xmit:        eth_transmit(arptable[arpentry].node, IP, len, buf);
  406.     }
  407.     return(1);
  408. }
  409.  
  410. /**************************************************************************
  411. TFTP - Try to load configuation file
  412. **************************************************************************/
  413. int tftp(name)
  414.     char           *name;
  415. {
  416.     int             retry = MAX_TFTP_RETRIES;
  417.     static unsigned short isocket = 2000;
  418.     unsigned short  osocket;
  419.     unsigned short  len, block = 1, prevblock = 0;
  420.     struct tftp_t  *tr;
  421.     struct tftp_t   tp;
  422.  
  423.     tp.opcode = htons(TFTP_RRQ);
  424.     len = (sprintf((char *)tp.u.rrq, "%s%coctet", name, 0)
  425.             - ((char *)&tp)) + 1;
  426.     if (!udp_transmit(arptable[ARP_SERVER].ipaddr, ++isocket, TFTP,
  427.         len, (char *)&tp))
  428.         return (0);
  429.     for (;;)
  430.     {
  431.         if (!await_reply(AWAIT_TFTP, isocket, NULL))
  432.         {
  433.             if (prevblock == 0 && retry-- > 0)
  434.             {    /* maybe initial request was lost */
  435.                 if (!udp_transmit(arptable[ARP_SERVER].ipaddr,
  436.                     ++isocket, TFTP, len, (char *)&tp))
  437.                     return (0);
  438.                 continue;
  439.             }
  440.             break;    /* timeout on other blocks */
  441.         }
  442.         tr = (struct tftp_t *)&packet[ETHER_HDR_SIZE];
  443.         if (tr->opcode == ntohs(TFTP_ERROR))
  444.         {
  445.             printf("TFTP error %d (%s)\r\n",
  446.                    ntohs(tr->u.err.errcode),
  447.                    tr->u.err.errmsg);
  448.             break;
  449.         }
  450.         if (tr->opcode != ntohs(TFTP_DATA))
  451.             break;
  452.         tp.opcode = htons(TFTP_ACK);
  453.         block = ntohs(tp.u.ack.block = tr->u.data.block);
  454.         osocket = ntohs(tr->udp.src);
  455.         len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4;
  456.         if (len > TFTP_MAX_PACKET)    /* shouldn't happen */
  457.             continue;        /* ignore it */
  458.         udp_transmit(arptable[ARP_SERVER].ipaddr, isocket,
  459.             osocket, TFTP_MIN_PACKET, (char *)&tp);    /* ack */
  460.         if (block <= prevblock)        /* retransmission */
  461.             continue;        /* don't process */
  462.         prevblock = block;
  463.         if (block == 1)
  464.         {
  465.             if (len == TFTP_MAX_PACKET &&
  466.                 (((unsigned short *)tr->u.data.download)[255] == 0xAA55 ||
  467.                 *((unsigned long *)tr->u.data.download) == 0x1B031336l))
  468.                 printf("Tagged file format");
  469.             else
  470.             {
  471.                 bcopy(tr->u.data.download, config_buffer, len);
  472.                 config_buffer[len] = 0;
  473.                 return (1);
  474.             }
  475.         }
  476.         if (!linux_tftp(block, tr->u.data.download, len))
  477.             break;
  478.         if (len < TFTP_MAX_PACKET)    /* End of data */
  479.             return (1);
  480.     }
  481.     return (0);
  482. }
  483.  
  484. /**************************************************************************
  485. BOOTP - Get my IP address and load information
  486. **************************************************************************/
  487. int bootp()
  488. {
  489.     int retry = MAX_BOOTP_RETRIES;
  490.     struct bootp_t bp;
  491.     unsigned long  starttime;
  492.     bzero(&bp, sizeof(struct bootp_t));
  493.     bp.bp_op = BOOTP_REQUEST;
  494.     bp.bp_htype = 1;
  495.     bp.bp_hlen = ETHER_ADDR_SIZE;
  496.     bp.bp_xid = starttime = currticks();
  497.     bcopy(arptable[ARP_CLIENT].node, bp.bp_hwaddr, ETHER_ADDR_SIZE);
  498.     while(retry--) {
  499.         udp_transmit(IP_BROADCAST, 0, BOOTP_SERVER,
  500.             sizeof(struct bootp_t), (char *)&bp);
  501.         if (await_reply(AWAIT_BOOTP, 0, NULL)) {
  502.             bcopy(&packet[ETHER_HDR_SIZE],(char *)&bootp_reply,sizeof(bootp_reply));
  503.             return(1); }
  504.         bp.bp_secs = htons((currticks()-starttime)/20);
  505.     }
  506.     return(0);
  507. }
  508.  
  509.  
  510. /**************************************************************************
  511. AWAIT_REPLY - Wait until we get a response for our request
  512. **************************************************************************/
  513. int await_reply(type, ival, ptr)
  514.     int type, ival;
  515.     char *ptr;
  516. {
  517.     unsigned long time;
  518.     struct    iphdr *ip;
  519.     struct    udphdr *udp;
  520.     struct    arprequest *arpreply;
  521.     struct    bootp_t *bootpreply;
  522.     struct    rpc_t *rpc;
  523.  
  524.     int    protohdrlen = ETHER_HDR_SIZE + sizeof(struct iphdr) +
  525.                 sizeof(struct udphdr);
  526.     time = currticks() + TIMEOUT;
  527.     while(time > currticks()) {
  528.         pollkbd();
  529.         if (eth_poll()) {    /* We have something! */
  530.                     /* Check for ARP - No IP hdr */
  531.             if ((type == AWAIT_ARP) &&
  532.                (packetlen >= ETHER_HDR_SIZE +
  533.                 sizeof(struct arprequest)) &&
  534.                (((packet[12] << 8) | packet[13]) == ARP)) {
  535.                 arpreply = (struct arprequest *)
  536.                     &packet[ETHER_HDR_SIZE];
  537.                 if ((arpreply->opcode == ntohs(ARP_REPLY)) &&
  538.                    bcompare(arpreply->sipaddr, ptr, 4)) {
  539.                     bcopy(arpreply->shwaddr,
  540.                         arptable[ival].node,
  541.                         ETHER_ADDR_SIZE);
  542.                     return(1);
  543.                 }
  544.                 continue;
  545.             }
  546.  
  547.                     /* Anything else has IP header */
  548.             if ((packetlen < protohdrlen) ||
  549.                (((packet[12] << 8) | packet[13]) != IP)) continue;
  550.             ip = (struct iphdr *)&packet[ETHER_HDR_SIZE];
  551.             if ((ip->verhdrlen != 0x45) ||
  552.                 ipchksum((unsigned short *)ip, sizeof(struct iphdr)) ||
  553.                 (ip->protocol != IP_UDP)) continue;
  554.             udp = (struct udphdr *)&packet[ETHER_HDR_SIZE +
  555.                 sizeof(struct iphdr)];
  556.  
  557.                     /* BOOTP ? */
  558.             bootpreply = (struct bootp_t *)&packet[ETHER_HDR_SIZE];
  559.             if ((type == AWAIT_BOOTP) &&
  560.                (packetlen >= (ETHER_HDR_SIZE +
  561.                  sizeof(struct bootp_t))) &&
  562.                (ntohs(udp->dest) == BOOTP_CLIENT) &&
  563.                (bootpreply->bp_op == BOOTP_REPLY)) {
  564.                 convert_ipaddr((char *)&arptable[ARP_CLIENT].ipaddr,
  565.                     bootpreply->bp_yiaddr);
  566.                 default_netmask();
  567.                 convert_ipaddr((char *)&arptable[ARP_SERVER].ipaddr,
  568.                     bootpreply->bp_siaddr);
  569.                 bzero(arptable[ARP_SERVER].node,
  570.                     ETHER_ADDR_SIZE);  /* Kill arp */
  571.                 convert_ipaddr((char *)&arptable[ARP_GATEWAY].ipaddr,
  572.                     bootpreply->bp_giaddr);
  573.                 bzero(arptable[ARP_GATEWAY].node,
  574.                     ETHER_ADDR_SIZE);  /* Kill arp */
  575.                 if (bootpreply->bp_file[0]) {
  576.                     bcopy(bootpreply->bp_file,
  577.                         kernel_buf, 128);
  578.                     kernel = kernel_buf;
  579.                 }
  580.                 decode_rfc1048(bootpreply->bp_vend);
  581.                 return(1);
  582.             }
  583.  
  584.                     /* TFTP ? */
  585.             if ((type == AWAIT_TFTP) &&
  586.                 (ntohs(udp->dest) == ival)) return(1);
  587.  
  588.                     /* RPC */
  589.             rpc = (struct rpc_t *)&packet[ETHER_HDR_SIZE];
  590.             if ((type == AWAIT_RPC) &&
  591.                (ntohs(udp->dest) == RPC_SOCKET) &&
  592.                (ntohl(rpc->u.reply.id) == ival) &&
  593.                (ntohl(rpc->u.reply.type) == MSG_REPLY)) {
  594. #ifdef    NETBOOT32
  595.                 rpc_id++;
  596. #endif    /* NETBOOT32 */
  597.                 return(1);
  598.             }
  599.         }
  600.     }
  601.     return(0);
  602. }
  603.  
  604. /**************************************************************************
  605. DECODE_RFC1048 - Decodes RFC1048 header
  606. **************************************************************************/
  607. void decode_rfc1048(p)
  608.     unsigned char *p;
  609. {
  610.     static char rfc1048_cookie[4] = RFC1048_COOKIE;
  611.     unsigned char *end = p + BOOTP_VENDOR_LEN,*q;
  612.     if (bcompare(p, rfc1048_cookie, 4)) { /* RFC 1048 header */
  613.         p += 4;
  614.         while(p < end) {
  615.             unsigned char c = *p;
  616.             if (c == RFC1048_PAD) {p++; continue;}
  617.             else if (c == RFC1048_END) {p = end; continue; }
  618.             else if (c == RFC1048_NETMASK) {bcopy(p+2,&netmask,4); }
  619.             else if (c == RFC1048_HOSTNAME) {
  620.                 bcopy(p+2,&nfsdiskless.my_hostnam,TAG_LEN(p));
  621.                 hostnamelen = (TAG_LEN(p)+3)&~3; }
  622.             else {
  623.                 printf("Unknown RFC1048-tag ");
  624.                 for(q=p;q<p+2+TAG_LEN(p);q++)
  625.                     printf("%x ",*q);
  626.                 printf("\n\r"); }
  627.             p += TAG_LEN(p) + 2;
  628.         }
  629.     }
  630. }
  631.  
  632. /**************************************************************************
  633. IPCHKSUM - Checksum IP Header
  634. **************************************************************************/
  635. unsigned short ipchksum(ip, len)
  636.     unsigned short *ip;
  637.     int len;
  638. {
  639.     unsigned long sum = 0;
  640.     len >>= 1;
  641.     while (len--) {
  642.         sum += *(ip++);
  643.         if (sum > 0xFFFF)
  644.             sum -= 0xFFFF;
  645.     }
  646.     return((~sum) & 0x0000FFFF);
  647. }
  648.  
  649.  
  650. /**************************************************************************
  651. CONVERT_IPADDR - Convert IP address from net to machine order
  652. **************************************************************************/
  653. void convert_ipaddr(d, s)
  654.     char *d,*s;
  655. {
  656.     *(d+3) = *s;
  657.     *(d+2) = *(s+1);
  658.     *(d+1) = *(s+2);
  659.     *d     = *(s+3);
  660. }
  661.